package model;

import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.ArrayList;

public class GameSocket extends Thread
{
	private PrintWriter out;
	private BufferedReader in;
	private ObjectOutputStream oos;

	private Socket socket;
	private int playerNumber;
	private ArrayList<GameTile> gameTiles;
	private GameQueue gameQueue;

	private Player p;

	// private int[] sideChoice = { 1, 1, 1, 1};

	public GameSocket(Socket socket, int playerNumber,
			ArrayList<GameTile> gameTiles, GameQueue gamePlayers)
	{
		try
		{
			this.socket = socket;
			socket.setTcpNoDelay(false);
			this.playerNumber = playerNumber;
			this.gameTiles = gameTiles;
			out = new PrintWriter(socket.getOutputStream(), true);
			in = new BufferedReader(new InputStreamReader(
					socket.getInputStream()));
			this.gameQueue = gamePlayers;
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}

	}

	public Socket getSocket()
	{
		return socket;
	}

	public void setSocket(Socket socket)
	{
		this.socket = socket;
	}

	public PrintWriter getOut()
	{
		return out;
	}

	public void setOut(PrintWriter out)
	{
		this.out = out;
	}

	public BufferedReader getIn()
	{
		return in;
	}

	public void setIn(BufferedReader in)
	{
		this.in = in;
	}

	public int getPlayerNumber()
	{
		return playerNumber;
	}

	public void setPlayerNumber(int playerNumber)
	{
		this.playerNumber = playerNumber;
	}

	@Override
	public void run()
	{

		try
		{
			while (getIn() != null)
			{
				int durr = getIn().read();

				System.out.println("Client no. " + getPlayerNumber() + " says "
						+ durr);
				synchronized (this)
				{
					switch (durr)
					{
					case 1:
						for (GameTile gT : gameTiles)
						{
							if ((gT.getxCoord() == 0 && gT.getyCoord() == 0)
									&& (!gT.isOccupied()))
							{
								getOut().write(1);

								setPlayer(new Player(getPlayerNumber(), true,
										0, 0));
								gT.setOccupied(true);
								p.start();
								System.out.println(p);
								this.notify();

							}
							else if ((gT.getxCoord() == 0 && gT.getyCoord() == 0)
									&& (gT.isOccupied()))
							{
								System.out
										.println("0,0 is taken, cannot choose");
								getOut().write(0);
							}
						}
						getOut().flush();

						break;
					case 2:
						for (GameTile gT : gameTiles)
						{
							if ((gT.getxCoord() == 0 && gT.getyCoord() == 8)
									&& (!gT.isOccupied()))
							{
								getOut().write(1);
								setPlayer(new Player(getPlayerNumber(), true,
										0, 8));
								gT.setOccupied(true);
								p.start();
								System.out.println(p);
								this.notify();
							}
							else if ((gT.getxCoord() == 0 && gT.getyCoord() == 8)
									&& (gT.isOccupied()))
							{
								System.out
										.println("0,8 is taken, cannot choose");
								getOut().write(0);
							}
						}
						getOut().flush();
						break;
					case 3:
						for (GameTile gT : gameTiles)
						{
							if ((gT.getxCoord() == 8 && gT.getyCoord() == 0)
									&& (!gT.isOccupied()))
							{
								getOut().write(1);
								setPlayer(new Player(getPlayerNumber(), true,
										8, 0));
								gT.setOccupied(true);
								p.start();
								System.out.println(p);
								this.notify();
							}
							else if ((gT.getxCoord() == 8 && gT.getyCoord() == 0)
									&& (gT.isOccupied()))
							{
								System.out
										.println("8,0 is taken, cannot choose");
								getOut().write(0);
							}
						}
						getOut().flush();
						break;
					case 4:
						for (GameTile gT : gameTiles)
						{
							if ((gT.getxCoord() == 8 && gT.getyCoord() == 8)
									&& (!gT.isOccupied()))
							{
								getOut().write(1);
								setPlayer(new Player(getPlayerNumber(), true,
										8, 8));
								gT.setOccupied(true);
								p.start();
								System.out.println(p);
							}
							else if ((gT.getxCoord() == 8 && gT.getyCoord() == 8)
									&& (gT.isOccupied()))
							{
								System.out
										.println("8,8 is taken, cannot choose");
								getOut().write(0);
								this.notify();
							}
						}
						getOut().flush();
						break;
					case 5:
						// Create game
						notifyThread();
						break;
					case 6:
						// Queue for game
						waitThread();
						break;
					case 7:
						// Move UP
						move(this, 7);
						updateBoard();
						break;
					case 8:
						// Move DOWN
						move(this, 8);
						updateBoard();
						break;
					case 9:
						// Move LEFT
						move(this, 9);
						updateBoard();
						break;
					case 10:
						// Move RIGHT
						move(this, 10);
						updateBoard();
						break;
					case 11:
						// Teleport 4:4
						teleport(this);
						updateBoard();
						break;
					case 12:

						// Teleport 4:4
						System.out.println("GameSocket 12 starting");
						ArrayList<GameTile> tempGT = new ArrayList<GameTile>();
						for (GameTile gT : gameTiles)
						{
							if (gT.isOccupied())
							{
								tempGT.add(gT);
							}
						}
						System.out.println("Occupado " + tempGT);
						FileOutputStream fileOut = new FileOutputStream(
								"loltiles.dat");
						oos = new ObjectOutputStream(fileOut);

						System.out.println("OOS Written");
						oos.writeObject(tempGT);
						oos.flush();
						oos.close();

						break;

					default:
						System.out.println("You got to default");
						getOut().write(0);
						getOut().flush();
						break;
					}

				}
			}
		}
		catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public void setPlayer(Player p)
	{
		this.p = p;
	}

	public Player getPlayer()
	{
		return p;
	}

	public boolean move(GameSocket gameSocket, int number) throws IOException
	{
		try
		{

			int moveUp = 0;
			int moveLeft = 0;

			if (number == 7)
			{
				moveUp = -1;
			}
			else if (number == 8)
			{
				moveUp = 1;
			}
			else if (number == 9)
			{
				moveLeft = -1;
			}
			else
			{
				moveLeft = 1;
			}

			for (GameTile gT : gameTiles)
			{
				if (((p.getPosX() + moveUp) == gT.getxCoord())
						&& ((p.getPosY() + moveLeft) == gT.getyCoord()))
				{

					System.out.println("*****************");

					if (gT.isOccupied() == false && gT.isTraversable() == true)
					{
						for (GameTile gT2 : gameTiles)
						{
							if (gT2.getxCoord() == p.getPosX()
									&& gT2.getyCoord() == p.getPosY())
							{
								gT2.setOccupied(false);
							}
						}
						// System.out.println("Error1");
						gT.setOccupied(true);
						gameSocket.getOut().write(1);
						gameSocket.getOut().flush();

						p.setPosX(p.getPosX() + moveUp);
						p.setPosY(p.getPosY() + moveLeft);

						System.out.println("Traversible");
						return true;

					}
					else if (gT.isTraversable() == false)
					{
						System.out.println("Crashed into a pillar at "
								+ gT.getxCoord() + ":" + gT.getyCoord());
						gameSocket.getOut().write(0);
						gameSocket.getOut().flush();
						return false;

					}
					else if (gT.isOccupied() == true)
					{
						System.out.println("Player at " + gT.getxCoord() + ":"
								+ gT.getyCoord() + " is blocking your path");
						gameSocket.getOut().write(0);
						gameSocket.getOut().flush();
						return false;
					}

				}
			}
			throw new Exception();
			// return false;
		}
		catch (Exception ex)
		{

			System.out.println("*****************");
			System.out.println("Crashed into a wall");
			gameSocket.getOut().write(0);
			gameSocket.getOut().flush();
			return false;
		}
	}

	public boolean teleport(GameSocket gameSocket) throws IOException
	{
		try
		{

			System.out.println("Teleporting to 4:4");

			for (GameTile gT : gameTiles)
			{
				if (((4) == gT.getxCoord()) && ((4) == gT.getyCoord()))
				{

					System.out.println("*****************");

					if (p.getTeleportCount() > 0)
					{
						if (gT.isOccupied() == false)
						{
							for (GameTile gT2 : gameTiles)
							{
								if ((p.getPosX() == gT2.getxCoord())
										&& (p.getPosY() == gT2.getyCoord()))
								{
									gT2.setOccupied(false);
								}
							}
							gT.setOccupied(true);
							gameSocket.getOut().write(1);
							gameSocket.getOut().flush();

							p.setPosX(4);
							p.setPosY(4);

							System.out.println("Teleportable");
							p.setTeleportCount(0);

						}
						else
						{
							System.out.println("4:4 is Occupied");
							gameSocket.getOut().write(2);
							gameSocket.getOut().flush();

						}
						return true;
					}
					else
					{
						System.out.println("You have 0 Teleports");
						gameSocket.getOut().write(0);
						gameSocket.getOut().flush();
						return true;
					}
				}
			}
			throw new Exception();

		}
		catch (Exception ex)
		{

			System.out.println("Weird Exception");
			gameSocket.getOut().write(0);
			gameSocket.getOut().flush();
			return false;
		}
	}

	public synchronized void waitThread()
	{
		System.out.println("Wait");

		try
		{
			System.out.println("Casting wait on " + this);
			gameQueue.addPlayer();
			getOut().write(2);
			getOut().flush();
			while (gameQueue.getNumPlayers() < 2)
			{
				Thread.sleep(2000);
			}

		}
		catch (InterruptedException e)
		{
			e.printStackTrace();
		}
		System.out.println("Stop wait to " + this);
		System.out.println("Stopped waiting returned 1");
		getOut().write(1);
		getOut().flush();

	}

	public synchronized void notifyThread()
	{
		System.out.println("Create and notify waiting thread");
		gameQueue.addPlayer();
		System.out.println("Current players = " + gameQueue.getNumPlayers());

		System.out.println("Sending OK to " + this);
		getOut().write(1);
		getOut().flush();
	}

	public void updateBoard()
	{

	}

}
